class room:
    id = " "
    WorkPlaces = 0
    VisitorPlaces = 0
    Near = []
    PossibleOptions = 0

    def __init__(self,id,WP,VP):
        self.id = id
        self.WorkPlaces = WP
        self.VisitorPlaces = VP



class person:
    id = ' '
    Profession = " "
    Garlic_Lover = True
    MaxNumberOfVisitors = 0
    AvailableRooms = 0

    def __init__(self,id,Proffesion,GL,MNOV):
        self.id = id
        self.Profession = Proffesion
        self.Garlic_Lover = GL
        self.MaxNumberOfVisitors = MNOV


def CheckBossAlone(person,room,personinroom):
    if(person.Profession == "Boss"):
        for key, value in personinroom.items():
            if(value == room):
                return False

    for key, value in personinroom.items():
        if(value == room):
            if(key.Profession == "Boss"):
                return False
    return True

def CheckSecretaryNearBoss(person,room,personinroom):
    if(person.Profession == "Secretary"):
        for key,value in personinroom.items():
            if(key.Profession == "Boss"):
                for x in value.Near:
                    if(x == room.id):
                        return True
        return False
    else:
        return True

def CheckITSupportNearBoss(person,room,personinroom):
    if(person.Profession == "ITsupport"):
        for key,value in personinroom.items():
            if(key.Profession == "Boss"):
                for x in value.Near:
                    if(x == room.id):
                        return True
        return False
    else:
        return True

def CheckGarlicLover(person, room, personinroom):
    if(person.Garlic_Lover == True):
        for key,value in personinroom.items():
            if(room == value):
                if(key.Garlic_Lover == False):
                    return False
    else:
        for key,value in personinroom.items():
            if(room == value):
                if(key.Garlic_Lover == True):
                    return False
    return True

def CheckVisitorSpace(person, room, personinroom):
    count = 0
    if(person.MaxNumberOfVisitors > 0):
        for key, value in personinroom.items():
            if(room == value):
                count = count + key.MaxNumberOfVisitors
    count = count + person.MaxNumberOfVisitors

    if(count > room.VisitorPlaces):
        return False
    else:
        return True

def CheckPlace(person,room,personinroom):
    count = 0
    for key, value in personinroom.items():
        if(room == value):
            count = count + 1
    count = count + 1

    if(count > room.WorkPlaces):
        return False
    else:
        return True 

def CheckAllConstraints(person,room,personinroom):
    return (CheckBossAlone(person,room,personinroom) and
            CheckSecretaryNearBoss(person,room,personinroom) and
            CheckITSupportNearBoss(person,room,personinroom) and
            CheckGarlicLover(person,room,personinroom) and
            CheckVisitorSpace(person, room, personinroom) and
            CheckPlace(person,room,personinroom))
                                    

#Persons
A = person('A',"Boss",True,5)
B = person('B',"Secretary",False,1)
C = person('C',"ITsupport",False,2)
D = person('D',"Boss",True,5)
E = person('E',"Secretary",False,1)
F = person('F',"Worker",False,3)
G = person('G',"Worker",False,2)
H = person('H',"Worker",True,0)
I = person('I',"Worker",True,1)

PersonList = [A,B,C,D,E,F,G,H,I]

#Rooms
T1 = room('T1',2,5)
T1.Near = ['T2','T7']
T2 = room('T2',3,2)
T2.Near = ['T1','T3','T6']
T3 = room('T3',1,3)
T3.Near = ['T2','T4','T5']
T4 = room('T4',1,3)
T4.Near = ['T3','T5']
T5 = room('T5',2,5)
T5.Near = ['T6','T4','T3']
T6 = room('T6',2,5)
T6.Near = ['T5','T7','T2']
T7 = room('T7',2,5)
T7.Near = ['T6','T1']

RoomList = [T1,T2,T3,T4,T5,T6,T7]

#The room allocation
PersonInRoom = {}

def allocate(personlist,roomlist,personinroom):
    return RecursiveAllocate(personlist,roomlist,personinroom)
   


def RecursiveAllocate(personlist,roomlist,personinroom):
    person = SelectUnassignedVariable(personlist,roomlist,personinroom)
    if(person == None):
        return personinroom
    roomlist = OrderDomainValues(person,roomlist,personinroom,personlist)
    for room in roomlist:
        if(CheckAllConstraints(person,room,personinroom) == True):
           personinroom[person] = room
           result = RecursiveAllocate(personlist,roomlist,personinroom)
           if (result != False):
               return result
           del personinroom[person]

    return False
        
 

def SelectUnassignedVariable(personlist,roomlist,personinroom):
    TempPersonList = []
    if(len(personinroom) == 0):
        for person in personlist:
            if(person.Profession == "Boss"):
                return person

    for person in personlist:
        if person not in personinroom:
            count = 0
            for x in roomlist:
                if(CheckAllConstraints(person,x,personinroom)):
                    count = count + 1
            person.AvailableRooms = count
            TempPersonList.append(person)
    if(len(TempPersonList) != 0):
        return min(TempPersonList, key = lambda x: x.AvailableRooms)
    else:
        return None
      

def OrderDomainValues(person,roomlist,personinroom,personlist):
    TempRoomList = []
    
    for room in roomlist:
        PossibleOptions = 0
        personinroom[person] = room

        for testperson in personlist:
            if testperson not in personinroom:
                count = 0
                for x in roomlist:
                    if(CheckAllConstraints(testperson,x,personinroom)):
                        count = count + 1
                PossibleOptions = PossibleOptions + count
        room.PossibleOptions = PossibleOptions
        del personinroom[person]
    
    TempRoomList = roomlist
    roomlist = []

    while(len(TempRoomList) != 0):
        BestRoom = max(TempRoomList, key = lambda x: x.PossibleOptions)
        roomlist.append(BestRoom)
        TempRoomList.remove(BestRoom)

    return roomlist



def PrintDict(personinroom):
    for key,value in personinroom.items():
        print("(",key.id,",",key.Profession,",",key.Garlic_Lover,",",key.MaxNumberOfVisitors,")",":",value.id)
        

allocate(PersonList,RoomList,PersonInRoom)
PrintDict(PersonInRoom)


                    
                      
    
    





